--[["
    desc: lua模拟基类
 "]]

--所以这里的第一个参数clz是table本身
local function new(clz, ...)
    local obj = {}
    local mt = rawget(clz, "_mt_")
    if not mt then
        mt = {
            __index = clz,
            __tostring = clz.__tostring,
            __gc = clz.__gc,
        }
        rawset(clz, "_mt_", mt)
    end
    
    --重要的是这句，clz的内容被作为mt表的__index键值，mt作为obj的元表
    setmetatable(obj, mt)

    --调用构造函数，这个构造函数一般在clz的范围内就被设置好了
    obj:ctor(...)

    --函数返回的是一个新table
    return obj
end

local function class(super)
    local superType = type(super)
    if superType ~= "function" and superType ~= "table" then
        superType = nil
        super = nil
    end
    local clz = {}

    super = super or {ctor = function() end}

    --rawset就是避过元表的__newindex方法对clz进行赋值，这句删掉应该也问题不大
    --rawset(clz, "__super", super)

    --这句非常关键元表的__index使在clz中找不到一个元素时就到super当中去找，符合面向对象的规范
    --当table名字作为函数名字的形式被调用的时候，会调用__call函数，结合clz.new的定义，使table.new函数被调时调用最上面定义的new函数
    setmetatable(clz, {__index = super, __call = new})

    function clz.new(...)
        --调用处，clz本身被作为一个值被算进参数里面
        return clz(...)
    end  
    return clz
end

return class